import { InboxOutlined } from '@ant-design/icons';
import { useMutation } from '@tanstack/react-query';
import { Col, Image, message, Row, Spin, Upload, UploadProps } from 'antd';
import { isString } from 'lodash';
import { memo, useRef } from 'react';
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
import GUI from 'three/examples/jsm/libs/lil-gui.module.min.js';
import { STLLoader } from 'three/examples/jsm/loaders/STLLoader.js';
import { v4 } from 'uuid';
import { getModel, uploadImg } from './api';
import { three_module_style } from './style';

const { Dragger } = Upload;

const Img2Model = () => {
  const containerRef = useRef<HTMLDivElement>(null);
  const modelContainerHeight = window.innerHeight - 80;

  const loadModal = (url: string) => {
    const container = containerRef.current;

    if (container) {
      const loader = new STLLoader();
      const scene = new THREE.Scene();
      const camera = new THREE.PerspectiveCamera(90, window.innerWidth / window.innerHeight, 1, 1000);
      const renderer = new THREE.WebGLRenderer();
      const controls = new OrbitControls(camera, renderer.domElement);
      const clock = new THREE.Clock();
      const light = new THREE.PointLight(0xffffff, 1000, 1000);
      const gui = new GUI();
      const gui_camera = gui.addFolder('相机控制');
      const gui_light = gui.addFolder('灯光控制');
      const mixer = null as THREE.AnimationMixer | null;
      let counter = 0

      container.innerHTML = '';
      scene.background = new THREE.Color('#000');

      camera.position.set(0, 0, -40);
      gui_camera.add(camera.position, 'x', -100, 100);
      gui_camera.add(camera.position, 'y', -100, 100);
      gui_camera.add(camera.position, 'z', -100, 100);
      light.position.set(-20, 20, 0);
      gui_light.add(light.position, 'x', -100, 100);
      gui_light.add(light.position, 'y', -100, 100);
      gui_light.add(light.position, 'z', -100, 100);
      gui.close();
      scene.add(light);
      container.appendChild(renderer.domElement);
      renderer.setSize(containerRef.current.clientWidth, containerRef.current.clientWidth / 1.7);

      const animate = () => {
        requestAnimationFrame( animate );
        if (mixer) {
          const delta = clock.getDelta();

          mixer.update(delta);
        }
        counter++;
        camera.position.x += counter >= 200 ? 0.01 : -0.01;
        light.position.x += counter >= 200 ? -0.25 : 0.25;
        if (counter>=600) {
          counter = -200;
        }
        controls.update();
        renderer.render(scene, camera);
      };

      loader.load(
        url,
        geometry => {
          const material = new THREE.MeshPhongMaterial({
            emissive: '#000000',
            side: THREE.DoubleSide,
            transparent: false,
          });
          const mesh = new THREE.Mesh(geometry, material);

          mesh.position.set(0, 62, 0);
          mesh.rotation.set(0, 0, 180);
          scene.add(mesh);
          animate();
        }
      );
    }
  };

  // useMount(() => {
  //   loadModal('/stl/model_1726401657.stl')
  // });

  const { data: imgRes, isPending: imgPending, mutate: imgMutate } = useMutation({
    mutationFn: uploadImg,
    onSuccess(res) {
      if (isString(res?.result?.path)) {
        message.destroy();
        message.success('上传成功');
        modelMutate({ path: res.result.path });
      }
    },
  });

  const { isPending: modelPending, mutate: modelMutate } = useMutation({
    mutationFn: getModel,
    onSuccess(res) {
      if (res?.result) {
        loadModal(res?.result)
      }
    },
  });

  const uploadProps: UploadProps = {
    name: 'file',
    accept: '.jpg',
    multiple: false,
    showUploadList: false,
    customRequest: (options) => {
      const container = containerRef.current;

      if (container) {
        container.innerHTML = '';
      }
      imgMutate({ file: options.file as File });
    }
  };

  return (
    <Row className={three_module_style} gutter={16}>
      <Col span={8}>
        <Dragger {...uploadProps} key={imgRes?.result?.id ?? v4()}>
          <Spin spinning={imgPending}>
              <p className='ant-upload-drag-icon'>
                <InboxOutlined />
              </p>
              <p className='ant-upload-text'>单击或拖动文件到此区域进行上传</p>
              <p className='ant-upload-hint'>支持单次或批量上传。</p>
            </Spin>
        </Dragger>
        <Image src={imgRes?.result?.path} />
      </Col>
      <Col span={16}>
        <Spin spinning={modelPending} tip='模型生成中...'>
          <div style={{ height: modelContainerHeight }} ref={containerRef}></div>
        </Spin>
      </Col>
    </Row>
  );
};

export default memo(Img2Model);